package com.example.demo.exception;

import com.example.demo.common.ResultAjax;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


@RestControllerAdvice
public class ExceptionControllerAdvice {

    /**
     * BindException：表单对象参数违反约束，仅对于表单提交有效（接收参数没有加@RequestBody注解），对于以json格式提交将会失效
     * MethodArgumentNotValidException：JSON请求参数违反约束，为json格式有效（接收参数加上@RequestBody注解）
     * ConstraintViolationException：单个参数校验失败（后端实际接收的一个字段）
     * @param e
     * @return
     */

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = {BindException.class, ConstraintViolationException.class, MethodArgumentNotValidException.class})
    public ResultAjax<Object> methodArgumentNotValidExceptionHandler(Exception e){
        BindingResult br=null;
        if (e instanceof MethodArgumentNotValidException){
            br=((MethodArgumentNotValidException) e).getBindingResult();
        } else if (e instanceof BindException){
            br=((BindException) e).getBindingResult();
        } else if (e instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> violations = ((ConstraintViolationException) e).getConstraintViolations();
            if (CollectionUtils.isEmpty(violations)){
                return ResultAjax.faild("500",e.getMessage());
            }
            Map<String, String> map = violations.stream().collect(Collectors.toMap(x -> {
                PathImpl path = (PathImpl) x.getPropertyPath();
                return path.getLeafNode().toString();
            }, ConstraintViolation::getMessage, (k1, k2) -> k2));
            return ResultAjax.faild("400",map.toString());
        }
        if (br.hasFieldErrors()){
            List<FieldError> errors = br.getFieldErrors();
            List<String> strings = new ArrayList<>(errors.size());
            for (FieldError error : errors) {
             strings.add(error.getField()+":"+error.getDefaultMessage());
            }
            return ResultAjax.faild("500",errors.toString());
        }
        return ResultAjax.faild("500","校验错误");
    }

    @ExceptionHandler(value = {IllegalArgumentException.class})
    public ResultAjax illegalArgumentExceptionHandler(IllegalArgumentException e){
        return ResultAjax.faild("500",e.getMessage());
    }
}
